package com.forest.core.util

import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.os.Build
import android.telephony.TelephonyManager
import android.util.Log
import java.io.IOException
import java.net.HttpURLConnection
import java.net.NetworkInterface
import java.net.SocketException
import java.net.URL

object NetWorkUtil {

    private const val TIMEOUT = 3000

    const val NETWORK_AVAILABLE = "available"

    const val NETWORK_CONNECTED = "connected"

    const val NETWORK_WIFI = "wifi"

    const val NETWORK_MOBILE = "mobile"

    const val NETWORK_2G = "2g"

    const val NETWORK_3G = "3g"

    interface NetworkChangeListener {
        fun onNetworkChange(networkStatus: String)
    }

    fun registerNetworkCallback(
        context: Context,
        networkChangeListener: NetworkChangeListener? = null
    ) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            context.run {
                val connectivityManager =
                    getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
                connectivityManager?.apply {
                    registerDefaultNetworkCallback(
                            object :ConnectivityManager.NetworkCallback() {
                        override fun onAvailable(network: Network?) {
                            super.onAvailable(network)
                            networkChangeListener?.onNetworkChange(NETWORK_AVAILABLE)
                        }

                        override fun onLost(network: Network?) {
                            super.onLost(network)
                            val linkProperties = getLinkProperties(network)
                            Log.i("registerNetworkCallback","${linkProperties == null}")
//                            networkInfo?.apply {
//                                Log.i("registerNetworkCallback","isConnected = $isConnected detailedState = $detailedState extraInfo = $extraInfo subtype = $subtype subtypeName = $subtypeName")
//                            }
                            networkChangeListener?.onNetworkChange(NETWORK_CONNECTED)
                        }

                        override fun onCapabilitiesChanged(
                            network: Network?,
                            networkCapabilities: NetworkCapabilities?
                        ) {
                            super.onCapabilitiesChanged(network, networkCapabilities)
                            networkCapabilities?.let {
                                if (it.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {

                                    if (it.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
                                        networkChangeListener?.onNetworkChange(NETWORK_WIFI)
                                    } else {
                                        networkChangeListener?.onNetworkChange(NETWORK_MOBILE)
                                    }
                                }
                            }
                        }

                    })
                }
            }
        } else {
            return
        }
    }

    private fun isNetworkInfoStatus(context: Context?, status: String): Boolean {
        context?.run {
            val manager =
                applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            manager.activeNetworkInfo?.run {
                when (status) {
                    NETWORK_AVAILABLE -> {
                        return this.isAvailable
                    }
                    NETWORK_CONNECTED -> {
                        return this.isConnected
                    }
                    NETWORK_WIFI -> {
                        return this.type == ConnectivityManager.TYPE_WIFI
                    }
                    NETWORK_MOBILE -> {
                        if (this.type == ConnectivityManager.TYPE_MOBILE) {
                            return this.isAvailable
                        }
                    }
                    NETWORK_2G -> {
                        return when (this.subtype) {
                            TelephonyManager.NETWORK_TYPE_EDGE,
                            TelephonyManager.NETWORK_TYPE_GPRS,
                            TelephonyManager.NETWORK_TYPE_CDMA -> {
                                true
                            }
                            else -> {
                                false
                            }
                        }
                    }
                    NETWORK_3G -> {
                        return this.type == ConnectivityManager.TYPE_MOBILE
                    }
                    else -> {
                        return false
                    }
                }
            }
        }
        return false
    }

    /**
     * check NetworkAvailable
     *
     * @param context
     * @return
     */
    @JvmStatic
    fun isNetworkAvailable(context: Context?): Boolean {
        return isNetworkInfoStatus(context, NETWORK_AVAILABLE)
    }

    /**
     * check NetworkConnected
     *
     * @param context
     * @return
     */
    fun isNetworkConnected(context: Context?): Boolean {
        return isNetworkInfoStatus(context, NETWORK_CONNECTED)
    }

    /**
     * isWifi
     *
     * @param context
     * @return boolean
     */
    @JvmStatic
    fun isWifi(context: Context?): Boolean {
        return isNetworkInfoStatus(context, NETWORK_WIFI)
    }

    /**
     * 判断MOBILE网络是否可用
     */
    fun isMobile(context: Context?): Boolean {
        return isNetworkInfoStatus(context, NETWORK_MOBILE)
    }

    /**
     * check is3G
     *
     * @param context
     * @return boolean
     */
    @JvmStatic
    fun is3G(context: Context?): Boolean {
        return isNetworkInfoStatus(context, NETWORK_3G)
    }

    /**
     * is2G
     *
     * @param context
     * @return boolean
     */
    @JvmStatic
    fun is2G(context: Context?): Boolean {
        return isNetworkInfoStatus(context, NETWORK_2G)
    }


    /**
     * 得到ip地址
     *
     * @return
     */
    @JvmStatic
    fun getLocalIpAddress(): String {
        var ret = ""
        try {
            val en = NetworkInterface.getNetworkInterfaces()
            while (en.hasMoreElements()) {
                val enumIpAddress = en.nextElement().inetAddresses
                while (enumIpAddress.hasMoreElements()) {
                    val netAddress = enumIpAddress.nextElement()
                    if (!netAddress.isLoopbackAddress) {
                        ret = netAddress.hostAddress.toString()
                    }
                }
            }
        } catch (ex: SocketException) {
            ex.printStackTrace()
        }

        return ret
    }


    /**
     * ping "http://www.baidu.com"
     *
     * @return
     */
    @JvmStatic
    private fun pingNetWork(): Boolean {
        var result = false
        var httpUrl: HttpURLConnection? = null
        try {
            httpUrl = URL("http://www.baidu.com").openConnection() as HttpURLConnection
            httpUrl.apply {
                connectTimeout = TIMEOUT
                connect()
                result = true
            }
        } catch (e: IOException) {
        } finally {
            httpUrl?.disconnect()
        }
        return result
    }

}